/**
 * MP Software.
 */
package controllers;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import models.Payment;
import models.Payroll;
import models.PayrollPeriod;
import models.Rate;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import play.mvc.Controller;
import service.CalculationResult;
import service.PaymentDeductionFacade;
import service.PayrollCalculatorFacade;
import service.PayrollRegisterResult;
import service.PayrollRegisterService;
import service.RateResolver;
import controllers.views.DeductionTypeView;
import controllers.views.PaymentTypeView;

/**
 * @author Jeremiah John M. Macariola
 *
 */
public class PayrollRegisterDownload extends Controller {

	@Inject
	private static RateResolver rateResolver;
	
    @Inject
    private static PayrollCalculatorFacade payrollCalculatorFacade;

    @Inject
    private static PaymentDeductionFacade paymentDeductionFacade;

    @Inject
    private static PayrollRegisterService payrollRegisterService;

    public static void download(Long payrollPeriodId) {
        PayrollPeriod payrollPeriod = PayrollPeriod.findById(payrollPeriodId);
        createExcelSheet(payrollPeriod);
        export();
    }

    private static void createExcelSheet(PayrollPeriod payrollPeriod) {
        try {
            generateExcelDocument(payrollPeriod);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void generateExcelDocument(PayrollPeriod payrollPeriod)
            throws IOException {
        Workbook wb = new HSSFWorkbook();
        CreationHelper createHelper = wb.getCreationHelper();
        Sheet sheet = wb.createSheet("new sheet");

        /*
         * Create the header.
         */
        Row row = sheet.createRow((short) 0);
        Cell cell = row.createCell(0);
        cell.setCellValue(payrollPeriod.client.name);
        row = sheet.createRow((short) 1);
        cell = row.createCell(0);
        cell.setCellValue("Payroll Register");
        row = sheet.createRow((short) 2);
        cell = row.createCell(0);
        cell.setCellValue(payrollPeriod.getFromDateFormatted() + " - "
                + payrollPeriod.getToDateFormatted());

        String electronicId = payrollPeriod.client.electronicId;

        /*
         * Create the Payment type header.
         */
        row = sheet.createRow((short) 4);
        int paymentDeductionTypeIndex = 1;
        for (PaymentTypeView paymentTypeView : paymentDeductionFacade
                .getPaymentTypes(electronicId)) {
            cell = row.createCell(paymentDeductionTypeIndex);
            cell.setCellValue(paymentTypeView.name);
            paymentDeductionTypeIndex += 2;
        }

        /*
         * Gross.
         */
        cell = row.createCell(paymentDeductionTypeIndex);
        cell.setCellValue("Gross");
        paymentDeductionTypeIndex += 2;

        /*
         * Create the Deduction type header.
         */
        for (DeductionTypeView deductionTypeView : paymentDeductionFacade
                .getDeductionTypes(electronicId)) {
            cell = row.createCell(paymentDeductionTypeIndex);
            cell.setCellValue(deductionTypeView.name);
            paymentDeductionTypeIndex++;
        }

        /*
         * Total Deduction.
         */
        cell = row.createCell(paymentDeductionTypeIndex);
        cell.setCellValue("Total Deds");
        paymentDeductionTypeIndex++;

        /*
         * Net Pay.
         */
        cell = row.createCell(paymentDeductionTypeIndex);
        cell.setCellValue("Net Pay");
        paymentDeductionTypeIndex++;

        /*
         * Iterate over employee and print its payments and deductions.
         */
        Rate rate = rateResolver.getRate(electronicId);
        PayrollRegisterResult result = payrollRegisterService.process(
                electronicId, payrollPeriod);
        Map<String, Float> employeePayments = result.getEmployeePayments();
        Map<Long, CalculationResult> calcResults = result
                .getCalculationResults();
        List<Payroll> payrolls = getPayrolls(payrollPeriod);
        short rowIndex = 5;
        for (Payroll payroll : payrolls) {
            row = sheet.createRow(rowIndex);

            int columnIndex = 0;
            cell = row.createCell(columnIndex);
            cell.setCellValue(payroll.employee.name);
            columnIndex++;

            Long employeeId = payroll.employee.id;
            CellStyle style = wb.createCellStyle();
            style.setAlignment(CellStyle.ALIGN_RIGHT);
            style.setDataFormat(createHelper.createDataFormat().getFormat(
                    "#,##0.00"));
            for (PaymentTypeView paymentTypeView : paymentDeductionFacade
                    .getPaymentTypes(electronicId)) {
                cell = row.createCell(columnIndex);

                Float paymentHr = employeePayments.get(employeeId
                        + paymentTypeView.name);
                if (paymentHr != null) {
                    cell.setCellValue(paymentHr);
                    cell.setCellStyle(style);
                    cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                }
                columnIndex++;

                Payment payment = Payment.find("byPayrollAndPaymentType",
                        payroll, paymentTypeView.name).first();
                cell = row.createCell(columnIndex);

                if (payment != null) {
                    BigDecimal calcPaymentResult = payrollCalculatorFacade
                            .calculatePayment(electronicId, rate, payment);
                    cell.setCellValue(calcPaymentResult.doubleValue());
                    cell.setCellStyle(style);
                    cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                }
                columnIndex++;
            }

            /*
             * Gross value.
             */
            CalculationResult calcResult = calcResults.get(employeeId);
            cell = row.createCell(columnIndex);
            cell.setCellValue(calcResult.grossIncome.doubleValue());
            cell.setCellStyle(style);
            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
            columnIndex++;

            /*
             * Name for deductions.
             */
            cell = row.createCell(columnIndex);
            cell.setCellValue(payroll.employee.name);
            columnIndex++;

            /*
             * Deductions.
             */
            Map<String, BigDecimal> employeeDeductions = result
                    .getEmployeeDeductions();
            for (DeductionTypeView deductionTypeView : paymentDeductionFacade
                    .getDeductionTypes(electronicId)) {
                cell = row.createCell(columnIndex);
                BigDecimal deductionHr = employeeDeductions.get(employeeId
                        + deductionTypeView.name);
                if (deductionHr != null) {
                    cell.setCellValue(deductionHr.doubleValue());
                    cell.setCellStyle(style);
                    cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                }
                columnIndex++;
            }

            /*
             * Total deds.
             */
            cell = row.createCell(columnIndex);
            cell.setCellValue(calcResult.totalDeduction.doubleValue());
            cell.setCellStyle(style);
            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
            columnIndex++;

            /*
             * Net pay.
             */
            cell = row.createCell(columnIndex);
            cell.setCellValue(calcResult.netPay.doubleValue());
            cell.setCellStyle(style);
            cell.setCellType(Cell.CELL_TYPE_NUMERIC);

            rowIndex++;
        }

        /*
         * Create and write the file.
         */
        DateFormat df = new SimpleDateFormat("MMMddyyyy");
        String fileName = "PayrollRegister-"
                + df.format(payrollPeriod.fromDate) + '-'
                + df.format(payrollPeriod.toDate);
        df = new SimpleDateFormat("HHmmssMMMddyyyy");
        fileName = fileName + '-' + df.format(new Date());
        fileName = fileName + ".xls";
        FileOutputStream fileOut = new FileOutputStream(fileName);
        wb.write(fileOut);
        fileOut.close();
    }

    private static List<Payroll> getPayrolls(PayrollPeriod payrollPeriod) {
        return payrollRegisterService.loadPayrolls(payrollPeriod);
    }

    private static void export() {
        // TODO Auto-generated method stub
    }

}
